#pragma once

#include "Thread.hpp"
#include "LockGuard.hpp"

#include <vector>
#include <queue>
#include <mutex>

#include <unistd.h>

using namespace ThreadNs;

static const int gnum = 5;

template <class T>
class ThreadPool;

template <class T>
class ThreadData
{
public:
    ThreadData(ThreadPool<T> *tp, std::string name)
        : _tp(tp), _name(name)
    {
    }

public:
    ThreadPool<T> *_tp;
    std::string _name;
};

template <class T>
class ThreadPool
{
public:
    static ThreadPool<T> *getInstance(const int &num = gnum)
    {
        if (nullptr == _tp)
        {
            _singleton_mtx.lock();
            if (nullptr == _tp)
            {
                _tp = new ThreadPool<T>(num);
            }
            _singleton_mtx.unlock();
        }
        return _tp;
    }

    ThreadPool<T> &operator=(const ThreadPool<T> &) = delete;
    ThreadPool(const ThreadPool &) = delete;

private:
    ThreadPool(const int &num = gnum)
        : _num(num)
    {
        for (int i = 0; i < _num; i++)
        {
            _threadpool.push_back(new Thread());
        }

        pthread_mutex_init(&_mutex, nullptr);
        pthread_cond_init(&_cond, nullptr);
    }

public:
    ~ThreadPool()
    {
        // for(int i = 0; i < _num; i++) delete _threadpool[i];
        for (const auto &t : _threadpool)
            delete t;
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_cond);
    }

    void run()
    {
        for (const auto &t : _threadpool)
        {
            ThreadData<T> *td = new ThreadData<T>(this, t->threadname());
            t->start(handlerTask, td);
            std::cout << t->threadname() << " is running..." << std::endl;
        }
    }

    static void *handlerTask(void *args)
    {
        ThreadData<T> *td = static_cast<ThreadData<T> *>(args);
        while (true)
        {
            {
                LockGuard lock(td->_tp->get_mutex());
                while (td->_tp->is_queue_empty())
                {
                    td->_tp->thread_wait(); // 队列为空则在条件变量下等待
                }
            }

            T t = td->_tp->Pop();

            // td->_tp->lock_queue();
            // while (td->_tp->is_queue_empty())
            // {
            //     td->_tp->thread_wait(); // 队列为空则在条件变量下等待
            // }
            // T t = td->_tp->Pop();
            // td->_tp->unlock_queue();

            std::string res = t();
            std::cout << td->_name << " 获取一个任务: " << t.task_to_string() << ", 已处理完成---> " << res << std::endl;
        }
        delete td;
        return nullptr;
    }

    void Push(const T &t)
    {
        LockGuard lock(&_mutex);
        _task_queue.push(t);
        pthread_cond_signal(&_cond);

        // pthread_mutex_lock(&_mutex);
        // _task_queue.push(t);
        // pthread_cond_signal(&_cond);
        // pthread_mutex_unlock(&_mutex);
    }

private:
    pthread_mutex_t *get_mutex()
    {
        return &_mutex;
    }

    bool is_queue_empty()
    {
        return _task_queue.empty();
    }

    void lock_queue()
    {
        pthread_mutex_lock(&_mutex);
    }

    void unlock_queue()
    {
        pthread_mutex_unlock(&_mutex);
    }

    void thread_wait()
    {
        pthread_cond_wait(&_cond, &_mutex);
    }

    T Pop()
    {
        T t = _task_queue.front();
        _task_queue.pop();
        return t;
    }

private:
    int _num;                          // 线程个数
    std::vector<Thread *> _threadpool; // 线程池
    std::queue<T> _task_queue;         // 任务队列

    pthread_cond_t _cond;   // 条件变量
    pthread_mutex_t _mutex; // 互斥锁

    static ThreadPool<T> *_tp;
    static std::mutex _singleton_mtx;
};

template <class T>
ThreadPool<T> *ThreadPool<T>::_tp = nullptr;

template <class T>
std::mutex ThreadPool<T>::_singleton_mtx;
